﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MethodWorx.CMS.Content;
using MethodWorx.Core.DomainModel;
using MethodWorx.CMS.UI.Models;
using MethodWorx.CMS.Plugins;
using MethodWorx.CMS.Configuration;
using MethodWorx.CMS.Services;
using MethodWorx.CMS.Administration;
using MethodWorx.CMS.UI.Application.ActionResults;
using MethodWorx.CMS.Plugins.ActionResults;
using MethodWorx.CMS.Workflow;
using MethodWorx.CMS.UI.Application;

namespace MethodWorx.CMS.UI.Controllers
{
    public class PageController : Controller
    {
        private ContentService service;
        private SchemaService schema;
        private IApplicationSettingsRepository applicationSettings;
        private IPluginRepository plugins;
        private WorkflowService workflowService;
        private IUnitOfWorkFactory unitOfWorkFactory;

        public PageController(SchemaService schema, ContentService service, WorkflowService workflowService, IApplicationSettingsRepository applicationSettings, IPluginRepository plugins)
        {
            this.service = service;
            this.applicationSettings = applicationSettings;
            this.plugins = plugins;
            this.schema = schema;
            this.workflowService = workflowService;
            this.unitOfWorkFactory = unitOfWorkFactory;
        }

       


        [HttpGet]
        public ActionResult EditProperty(Guid id, string name)
        {
            //  get the page
            var page = this.service.GetPageById(id);
            //  and use it
            if (page == null)
                throw new BusinessRuleException("Page not found");

            return View("Properties", new ConfigurePropertiesModel(page, 0, true, name) { ShowGrouping = false });
        }

        [HttpPost]
        [ValidateInput(false)]
        public ActionResult EditProperty(Guid id, int? selectedPropertyIndex, PropertyDetails<object>[] propertyDetails, string command, string name)
        {
            //  get the page
            var page = this.service.GetPageById(id);
            //  and use it
            if (page == null)
                throw new BusinessRuleException("Page not found");

            var model = new ConfigurePropertiesModel(page.Template, selectedPropertyIndex ?? 0, true);
            //model.Properties = propertyDetails ?? new PropertyDetails<object>[] { };
            foreach (var pd in propertyDetails)
            {
                var found = model.Properties.FirstOrDefault(p => p.Name == pd.Name);
                if (found != null)
                    ((ICustomPropertyDetails)found.Custom).CopyValueFrom((ICustomPropertyDetails)pd.Custom);
            }

            switch (command)
            {
                case "save":
                    if (this.ModelState.IsValid)
                    {
                        //
                        //  ok, we are valid, so lets save
                        this.ViewData["message"] = "Property was successfully saved";
                        this.service.UpdatePageProperties(id, model.Properties.Cast<IPropertyDetails>());
                    }
                    break;
            }

            return View("Properties", new ConfigurePropertiesModel(page, 0, true, name) { ShowGrouping = false });
        }

        [HttpGet]
        public ActionResult EditContentItemProperty(Guid id, Guid contentItemId, string name)
        {
            //  get the page
            var page = this.service.GetPageById(id);
            //  and use it
            if (page == null)
                throw new BusinessRuleException("Page not found");

            var contentItem = page.ChildContent.Where(c => c.Id == contentItemId).FirstOrDefault();
            if (contentItem == null)
                throw new BusinessRuleException("Content Item Not Found");

            return View("Properties", new ConfigurePropertiesModel(contentItem, 0) { ShowGrouping = false });
        }


        [HttpPost]
        [ValidateInput(false)]
        public ActionResult EditContentItemProperty(Guid id, Guid contentItemId, int? selectedPropertyIndex, string name, PropertyDetails<object>[] propertyDetails, string command)
        {
            //  get the page
            var page = this.service.GetPageById(id);
            //  and use it
            if (page == null)
                throw new BusinessRuleException("Page not found");

            var contentItem = page.ChildContent.Where(c => c.Id == contentItemId).FirstOrDefault();
            if (contentItem == null)
                throw new BusinessRuleException("Content Item Not Found");

            var model = new ConfigurePropertiesModel(contentItem.Template, selectedPropertyIndex ?? 0);
            
            foreach (var pd in propertyDetails)
            {
                var found = model.Properties.FirstOrDefault(p => p.Name == pd.Name);
                if (found != null)
                    ((ICustomPropertyDetails)found.Custom).CopyValueFrom((ICustomPropertyDetails)pd.Custom);
            }

            switch (command)
            {
                case "save":
                    if (this.ModelState.IsValid)
                    {
                        //
                        //  ok, we are valid, so lets save
                        this.ViewData["message"] = "Content Item was successfully saved";
                        this.service.UpdateContentItemProperties(contentItemId, model.Properties.Cast<IPropertyDetails>());
                    }
                    break;
            }

            
            return View("Properties", new ConfigurePropertiesModel(contentItem, 0) { ShowGrouping = false });
        }


        [HttpGet]
        public ActionResult Properties(Guid id)
        {
            //  get the page
            var page = this.service.GetPageById(id);
            //  and use it
            if (page == null)
                throw new BusinessRuleException("Page not found");

            return View(new ConfigurePropertiesModel(page, 0, true));
        }

        [HttpPost]
        [ValidateInput(false)]
        public ActionResult Properties(Guid id, int? selectedPropertyIndex, PropertyDetails<object>[] propertyDetails, string command)
        {
            //  initialize the model if none are present
            propertyDetails = propertyDetails ?? new PropertyDetails<object>[] { };

            //  get the page
            var page = this.service.GetPageById(id);
            //  and use it
            if (page == null)
                throw new BusinessRuleException("Page not found");

            var model = new ConfigurePropertiesModel(page, selectedPropertyIndex ?? 0, true);
            //model.Properties = propertyDetails ?? new PropertyDetails<object>[] { };
            foreach (var pd in propertyDetails)
            {
                var found = model.Properties.FirstOrDefault(p => p.Name == pd.Name);
                if (found != null)
                    ((ICustomPropertyDetails)found.Custom).CopyValueFrom((ICustomPropertyDetails)pd.Custom);
            }

            switch (command)
            {
                case "save":
                    if (this.ModelState.IsValid)
                    {
                        //
                        //  ok, we are valid, so lets save
                        this.service.UpdatePageProperties(id, model.Properties.Cast<IPropertyDetails>());
                        this.ViewData["message"] = "The page properties have been saved";
                    }
                    break;
            }

            return View(model);
        }

        [AcceptVerbs(HttpVerbs.Get)]
        public JsonResult GetIdeExtensions(Guid id)
        {
            List<object> extensions = new List<object>();

            Page page = this.service.GetPageById(id);
            PluginFactory factory = new PluginFactory(this.applicationSettings, this.plugins);
            if (page != null)
            {
                foreach (var extension in factory.GetIdeExtensionsForPage(page))
                {
                    extensions.Add(new
                    {
                        Id = extension.Id,
                        Name = extension.DisplayName
                    });
                }
            }

            return Json(extensions.ToArray(), JsonRequestBehavior.AllowGet);
        }

     

    

        [HttpGet]
        public ActionResult System(Guid id)
        {
            var model = new PageSystemModel(id, this.service);
            return View(model);
        }

        [HttpPost]
        public ActionResult System(Guid id, string submit)
        {
            PageSystemModel model;
            if (submit == "publish")
            {
                //
                //  ok, use the content service
                var page = this.service.PublishPage(id);
                model = new PageSystemModel(page);
                this.ViewData["message"] = "Page was successfully published";
            }
            else if(submit == "save")
            {
                model = new PageSystemModel(id, service);
                this.TryUpdateModel(model.Request, "Request");
                service.UpdatePage(model.Request);
                this.ViewData["message"] = "Page was successfully saved";
            }
            else
                model = new PageSystemModel(id, service);
            
            return View(model);
        }

        public ActionResult Publish(Guid id)
        {
            //
            //  ok, use the content service
            var page = this.service.PublishPage(id);
            return Json(new { success = true }, JsonRequestBehavior.AllowGet);
        }

        [HttpGet]
        public ActionResult CreateWorkflowStep(Guid id, string workflow, Guid? stepId)
        {
            var page = this.service.GetPageById(id);
            if (page == null)
                throw new BusinessRuleException("Page Not Found");

            var model = new EditWorkflowModel(page, this.service);
            model.CurrentWorkflowName = workflow;

            var components = new List<IWorkflowComponent>();

            foreach (var plugin in this.plugins.All().OfType<SafePlugin>())
            {
                if (plugin.Is<IWorkflowPlugin>())
                {
                    components.AddRange(plugin
                        .Invoke<IWorkflowPlugin, IEnumerable<IWorkflowComponent>>(p => p.GetWorkflowComponents()));
                }
            }

            model.Components = components;

            return View(model);
        }

        [HttpPost]
        public ActionResult CreateWorkflowStep(Guid id, string workflow, Guid? stepId, string submit, Guid? component)
        {
            var page = this.service.GetPageById(id);
            if (page == null)
                throw new BusinessRuleException("Page Not Found");

            var model = new EditWorkflowModel(page, this.service);
            model.CurrentWorkflowName = workflow;

            var components = new List<IWorkflowComponent>();

            foreach (var plugin in this.plugins.All().OfType<SafePlugin>())
            {
                if (plugin.Is<IWorkflowPlugin>())
                {
                    components.AddRange(plugin
                        .Invoke<IWorkflowPlugin, IEnumerable<IWorkflowComponent>>(p => p.GetWorkflowComponents()));
                }
            }

            model.Components = components;

            if (submit == "cancel")
                return new CloseDialogResult();
            else
            {
                if (component == null)
                {
                    this.ViewData["error"] = "Please choose a component";
                    return View(model);
                }
                else
                {
                    Guid componentId = model.Components.First(c => c.Id == component.Value).ConfigurationIdeExtension.Id;

                    return Redirect("~/Plugin/Page/" + componentId + "/" + id + "?workflow=" + workflow + "&stepId=&parentStepId=" + stepId);
                }
            }
        }

        [HttpGet]
        public JsonResult DeleteWorkflowStep(Guid id, string workflow, Guid stepId)
        {
            var page = this.service.GetPageById(id);
            if (page == null)
                throw new BusinessRuleException("Page Not Found");

            var model = new EditWorkflowModel(page, this.service);
            model.CurrentWorkflowName = workflow;

            this.workflowService.DeleteStep(page, workflow, stepId);

            return Json(new { Success = true }, JsonRequestBehavior.AllowGet);
        }

        [HttpGet]
        public ActionResult EditWorkflow(Guid id, string name)
        {
            var page = this.service.GetPageById(id);
            if (page == null)
                throw new BusinessRuleException("Page Not Found");

            var model = new EditWorkflowModel(page, this.service);
            model.CurrentWorkflowName = name;

            var components = new List<IWorkflowComponent>();

            foreach (var plugin in this.plugins.All().OfType<SafePlugin>())
            {
                if (plugin.Is<IWorkflowPlugin>())
                {
                    components.AddRange(plugin
                        .Invoke<IWorkflowPlugin, IEnumerable<IWorkflowComponent>>(p => p.GetWorkflowComponents()));
                }
            }

            model.Components = components;

            return View(model);
        }

      

    }
}
